package compilers.condition;

import java.io.BufferedWriter;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;

import compilers.Node;
import compilers.node.Identifier;
import compilers.stmt.FunctionType;
import compilers.table.MemScope;
import compilers.types.Type;

public class FuncCall extends Factor {
	Identifier fIdentifier;
	Vector<Param> fParameters = new Vector<Param>();
	FunctionType fFunction;
	
	public FuncCall(Identifier fIdentifier, Vector<Param> fParameters, FunctionType fFunction) {
		this.fIdentifier = fIdentifier;
		this.fParameters = fParameters;
		this.fFunction = fFunction;
	}
	
	public void print(int tab) {
		for (int i=1;i<=tab;i++){System.out.print("\t");}System.out.print("|-");
		System.out.println("FuncCall");
		fIdentifier.print(tab+1);
		Enumeration<Param> enumeration = fParameters.elements();
		while(enumeration.hasMoreElements()){
			((Node) enumeration.nextElement()).print(tab+1);
		}  
	}
	
	public Type compute() {
		return null;
	}
	
	public void arrayIndices(int index, MemScope scope, Vector<Integer> set, String name, Type type, BufferedWriter writer) throws IOException {
		Vector<Integer> ind = scope.getArray(name).getIndices(null);
		if (index < ind.size()) {
			for (int i = 0; i < ind.get(index).intValue(); i++) {
				set.set(index, i);
				arrayIndices((index+1), scope, set, name, type, writer);
			}
		} else {
			for (int i = 0; i < set.size(); i++) {
				name += "[" + set.get(i).intValue() + "]";
			}
			type.setfIdentifier(new Identifier(name));
			type.generate(writer, scope);
		}
	}

	public void generate(BufferedWriter writer, MemScope scope) throws IOException {
		if (this.getfRes() == null) {
			//System.out.println("FRES NULL IN CALL");
			//this.setfRes(new VoidType(true));
		}
		int mst = 1 + scope.getDepth(-1) - scope.getFunctionDepth(fIdentifier.getfIdentifier());
		writer.write("mst " + mst + "\n");
		// put param on stack
		int countParam = 0;
		for (int i = 0; i < fParameters.size(); i++) {
			if (fParameters.get(i).getType() == null) {
				fParameters.get(i).setfRes(this.getfRes());
				fParameters.get(i).generate(writer, scope);
				countParam++;
			} else {
				String name = fFunction.getfParameters().get(i).getType().getfIdentifier().getfIdentifier();			
				
				if ((scope.isArray(name)) && (fParameters.get(i).getIdentifier().getIndices(null).isEmpty() )) {
					Vector<Integer> set = new Vector<Integer>();
					Vector<Integer> ind = scope.getArray(name).getIndices(null);
					for (int j = 0; j < ind.size(); j++) {
						countParam += ind.get(i).intValue();
						set.add(0);
					}
					//String orig = name;
					char c[] = name.toCharArray();
					for (int k = 0; k < c.length; k++) {
						if (c[k] == '[') {
							name = name.substring(0, k);
							break;
						}
					}
					fParameters.get(i).getType().setfRes(fFunction.getfParameters().get(i).getType());
					arrayIndices(0, scope, set, name, fParameters.get(i).getType(), writer);
					
				} else {
					countParam++;
					fParameters.get(i).getType().setfRes(fFunction.getfParameters().get(i).getType());
					fParameters.get(i).getType().generate(writer, scope);
				}
			}
		}
		
		if (scope.hasFunction(fIdentifier.getfIdentifier())) {
			writer.write("cup " + countParam + " func_" + fIdentifier.getfIdentifier() + "_" + scope.getName() + "\n");
		} else {
			writer.write("cup " + countParam + " func_" + fIdentifier.getfIdentifier() + "\n");
		}
		// convert return type
		if (getfRes() != null) {
			if (fFunction.getReturnType().getPType() != getfRes().getPType()) {
				writer.write("conv " + fFunction.getReturnType().getPType() + " " + getfRes().getPType() + "\n");
			}
		}
	}
}
